package controllers.mockController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.StringTokenizer;


import person.Customer;
import person.Employee;
import person.Guest;
import person.User;
import transaction.Transaction;
import budget.Budget;
import budget.Request;
import budget.Service;
import contract.EmployeeContract;
import contract.EventContract;
import controllers.Checks;
import controllers.ExceptionsTypes;
import controllers.Permission;
import controllers.PermissionList;
import controllers.interfaces.DataController;
import event.Event;

public class MockController implements DataController{
	public MockController(){
		src=new MockDataSource();
	}
	@Override
	public void login(String userName, String password) throws Exception {
		if(online){
			Thread.sleep(LATENCY);
			String tok=src.getToken(userName, password);
			if (tok!=null){this.token=tok;return;}
			else throw new Exception("LOGIN_ERROR");
		}
		else
			throw new Exception("CONNECTION_ERROR");
	}

	@Override
	public void logout() throws Exception {
		Thread.sleep(LATENCY);
		this.token=null;
		src.unableToken(token);
	}

	@Override
	public User getCurrentUser() throws Exception {
		Thread.sleep(LATENCY);
		User currentUser =src.getCurrentLogged(token);
		if (currentUser!=null)
			return currentUser;
		else throw new Exception("INVALID_TOKEN");
	}

	
	public void registerUser(User user, String userName, String password)throws Exception {		
		Thread.sleep(LATENCY);
		Checks.checkUser(userName, password,false);
		if(user instanceof Customer)
			Checks.checkCustomer((Customer)user);
		else
		//	Checks.checkEmployee((Employee)user);
		this.src.registerUser(user, userName, password);
	}

	@Override
	public void removeUser(User user) throws Exception {	
		Thread.sleep(LATENCY);
	}

	@Override
	public void registerRequest(Request request) throws Exception {
		Thread.sleep(LATENCY);
		if (token!=null){
			Checks.checkRequest(request);
			src.getGeneratedRequests().add(request);
		}else 
			throw new Exception(ExceptionsTypes.INVALID_TOKEN.name());
	}
	@Override
	public void denyRequest(Request request, String motivation) throws Exception {
		Thread.sleep(LATENCY);
		src.getGeneratedRequests().remove(request);

	}
	@Override
	public Collection<Request> getRequests(String searchTherms)	throws Exception {
		Thread.sleep(LATENCY);
		LinkedList<Request> ret=new LinkedList<Request>();
		HashMap<String,String> vals=this.searchParser(searchTherms);
		if (vals.containsKey("REQUEST")){
			Request req=(Request) src.getElem(Long.parseLong(vals.get("REQUEST")));
			if (req!=null){ret.add(req);}
		}else if(!(new PermissionList(this.getPermissions()).can(Permission.BUDGETS_VIEW_ALL))){
			ret.addAll(src.getGeneratedRequests(src.getCurrentLogged(token)));
		}else{ret.addAll(src.getGeneratedRequests());}
		return ret;
	}
	@Override
	public void removeRequest(Request request)throws Exception {
		Thread.sleep(LATENCY);
		src.getGeneratedRequests().remove(request);
	}
	@Override
	public Budget acceptRequest(Request request) throws Exception {
		Thread.sleep(LATENCY);
		if (token!=null){
			src.getGeneratedRequests().remove(request);
			Budget bd=new Budget(src.getLastId(), request);
			GregorianCalendar lastDate = new GregorianCalendar();
			lastDate.add(GregorianCalendar.MONTH, 6);
			bd.setLastDate(lastDate);
			bd.calculateTotalCostWhitoutAdjustment();
			//Checks.checkBudget(bd); non si può fare senza db!!
			src.getGeneratedBudgets().add(bd);
			return bd;
			
		}else 
			throw new Exception(ExceptionsTypes.INVALID_TOKEN.name());
		
	}

	@Override
	public Collection<EventContract> getEventContracts(String searchTerms) throws Exception {
		Thread.sleep(LATENCY);
		LinkedList<EventContract> ret=new LinkedList<EventContract>();
		HashMap<String,String> vals=this.searchParser(searchTerms);
		if (vals.containsKey("CONTRACT")){
			EventContract contr=(EventContract) src.getElem(Long.parseLong(vals.get("CONTRACT")));
			if (contr!=null){ret.add(contr);}
		}else ret.addAll(src.getGeneratedEventContracts());
		return ret;
	}

	@Override
	public void acceptEventContract(EventContract contract) throws Exception {
		Thread.sleep(LATENCY);
	}

	@Override
	public Collection<Budget> getBudgets(String searchTerms) throws Exception {
		Thread.sleep(LATENCY);
		LinkedList<Budget> ret=new LinkedList<Budget>();
		HashMap<String,String> vals=this.searchParser(searchTerms);
		if (vals.containsKey("BUDGET")){
			Budget budg=(Budget) src.getElem(Long.parseLong(vals.get("BUDGET")));
			if (budg!=null){ret.add(budg);}
		}else ret.addAll(src.getGeneratedBudgets());
		return ret;
	}

	@Override
	public void modifyBudget(Budget budget) throws Exception {
		Thread.sleep(LATENCY);
		budget.calculateTotalCostWhitoutAdjustment();
		for(Budget budg:src.getGeneratedBudgets()){
			if (budg.getId()==budget.getId()){
				 Checks.checkBudget(budget);
				 src.getGeneratedBudgets().remove(budg);
				 src.getGeneratedBudgets().add(budget);
			} 
		}
	}
	@Override
	public EventContract acceptBudget(Budget budget) throws Exception {
		Thread.sleep(LATENCY);

		for (Budget bdg:src.getGeneratedBudgets()){
			if (bdg.getId()==budget.getId()){
				src.getGeneratedBudgets().remove(bdg);
				EventContract cntr=new EventContract(src.getLastId(),new GregorianCalendar(), budget.getLastDate(), "", budget);
				src.getGeneratedEventContracts().add(cntr);
				return cntr;
			}
		}
		return null;
	}
	@Override
	public Collection<Event> getEvents(String searchTerms) throws Exception {
		Thread.sleep(LATENCY);
		LinkedList<Event> filtered=new LinkedList<Event>();
		HashMap<String,String> vals=this.searchParser(searchTerms);
		if(vals.isEmpty())
			filtered.addAll(src.getGeneratedEvents());
		else{
			if (vals.containsKey("EVENT")){
				Event e =(Event) src.getElem(Long.parseLong(vals.get("EVENT")));
				if (e!=null){filtered.add(e);}
			}if(vals.containsKey("STATE")){
				for(Event e: src.getGeneratedEvents())
					if(e.getEventState().getName().equalsIgnoreCase(vals.get("STATE")))
						filtered.add(e);
			}if(vals.containsKey("KeyWord"))
				for(Event e: src.getGeneratedEvents())
					if(e.contains(vals.get("KeyWord")))
						filtered.add(e);
		}
		return filtered;
	}

	@Override
	public void nextState(Event evento) throws Exception {
		Thread.sleep(LATENCY);		
	}
	private HashMap<String,String> searchParser(String query){
		HashMap<String,String> vals=new HashMap<String,String>();
		if (query.contains(";")){
			int kwCount=0;
			StringTokenizer strTok=new StringTokenizer(query,";");
			while(strTok.hasMoreTokens()){
				String tk=strTok.nextToken();
				if (tk.contains(":")){
					StringTokenizer strTok1=new StringTokenizer(tk,":");
					vals.put(strTok1.nextToken(), strTok1.nextToken());
				}
				else vals.put("KeyWord"+(kwCount++),tk);
			}
		}else
			if (query.contains(":")){
				StringTokenizer strTok1=new StringTokenizer(query,":");
				vals.put(strTok1.nextToken(), strTok1.nextToken());
			}
			else vals.put("KeyWord",query);
		return vals;
	}
	@SuppressWarnings("incomplete-switch")
	@Override
	public PermissionList getPermissions() throws Exception {
		Thread.sleep(LATENCY);
		User usr=src.getCurrentLogged(token);
		if (usr instanceof Employee){
			switch(((Employee) usr).getRole()){
				case RAPRESENTANT:return new PermissionList(getRepresentantPermissions());
			}
		}else if (usr instanceof Customer)return new PermissionList(getCustomerPermissions());
		else if(usr instanceof Root) return new PermissionList(getAllPermissions());
		return new PermissionList();
	}
	public Collection<Permission> getAllPermissions(){
		LinkedList<Permission> permissions=new LinkedList<Permission>();
		for(Permission perm:Permission.values()){
			permissions.add(perm);
		}
		return permissions;
	}
	public Collection<Permission> getCustomerPermissions(){
		LinkedList<Permission> permissions=new LinkedList<Permission>();
		permissions.add(Permission.REQUESTS_CREATE);
		permissions.add(Permission.REQUESTS_VIEW);
		return permissions;
	}
	private Collection<Permission> getRepresentantPermissions(){
		LinkedList<Permission> permissions=new LinkedList<Permission>();
		permissions.add(Permission.REQUESTS_CREATE_ALL);
		permissions.add(Permission.REQUESTS_VIEW_ALL);
		permissions.add(Permission.REQUESTS_MANAGE);
		return permissions;
	}
	@Override
	public Collection<Employee> getEmployees() throws Exception {
		Thread.sleep(LATENCY);
		return src.getGeneratedEmployees();
	}
	@Override
	public Collection<Customer> getCustomers() throws Exception {
		Thread.sleep(LATENCY);

		return null;
	}
	@Override
	public Collection<Guest> getGuests(Event evt) throws Exception {
		Thread.sleep(LATENCY);
		return null;
	}
	@Override
	public Collection<Service> getServices() throws Exception {
		Thread.sleep(LATENCY);
		return src.getGeneratedServices();
	}
	@Override
	public void addService(Service serv) throws Exception {
		Thread.sleep(LATENCY);
		for(Service srv:src.getGeneratedServices()){
			if (srv.equals(serv)){
				srv=serv;
				return;
			}
		}
		src.getGeneratedServices().add(serv);
	}
	@Override
	public void removeBudget(Budget budget) throws Exception {		
	}
	@Override
	public void modifyService(Service serv) throws Exception {
		this.addService(serv);
	}
	private MockDataSource src;
	private String token;
	private static final long LATENCY=0;
	private boolean online = true;
	@Override
	public void revertEventContract(EventContract contract) throws Exception {		
	}
	@Override
	public void removeService(Service serv) throws Exception {
	}
	
	@Override
	public Collection<EmployeeContract> getEmployeeContracts() throws Exception {
		return null;
	}
	
	public void acceptEmployeeContract1(EmployeeContract employeeContract)throws Exception {

	}
	@Override
	public void firesEmployee(EmployeeContract employeeContract)
			throws Exception {
		
	}
	
	public void registerUser1(User user, String userName, String password)
			throws Exception {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void acceptEmployeeContract(EmployeeContract employeeContract)
			throws Exception {
		// TODO Auto-generated method stub
		
	}
	@Override
	public ArrayList<Transaction> getTransactions() throws Exception {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public void addTransaction(Transaction transaction) throws Exception {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void createSystemUser() throws Exception {
		// TODO Auto-generated method stub
		
	}
	@Override
	public void setSystemUser(String userName, String password)
			throws Exception {
		// TODO Auto-generated method stub
		
	}
	@Override
	public Map<Integer, Map<String, Double>> getAllStats() throws Exception {
		// TODO Auto-generated method stub
		return null;
	}
	
	@Override
	public void modifyUserPassword(String password) throws Exception {
		// TODO Auto-generated method stub
		
}
	@Override
	public void payWages() throws Exception {
		// TODO Auto-generated method stub
		
	}
	@Override
	public Collection<Transaction> getWagesTransactions() throws Exception {
		// TODO Auto-generated method stub
		return null;
	}
		
	}